home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (c) 1992 The Geometry Center; University of Minnesota
- 1300 South Second Street; Minneapolis, MN 55454, USA;
-
- This file is part of geomview/OOGL. geomview/OOGL is free software;
- you can redistribute it and/or modify it only under the terms given in
- the file COPYING, which you should have received along with this file.
- This and other related software may be obtained via anonymous ftp from
- geom.umn.edu; email: software@geom.umn.edu. */
-
- /* Authors: Charlie Gunn, Stuart Levy, Tamara Munzner, Mark Phillips */
-
- /*
- * iterate.c -- iteration over OOGL hierarchies
- */
-
- #include <geomclass.h>
- #include "listP.h"
- #include "tlistP.h"
- #include "instP.h"
- #include "sphereP.h"
- #include "discgrpP.h"
-
- #define UNKNOWN 0
- #define LIST 1
- #define TLIST 2
- #define INST 3
- #define SPHERE 4
- #define DISCGRP 5
- #define OTHER 6
-
- #define VALID 0x13ac2480 /* Magic number */
-
- struct istate { /* Iteration state structure: per nest lvl */
- struct istate *parent;
- Geom *g;
- int kind;
- int seq; /* Seq number within Tlist */
- Transform Ti;
- };
-
- struct GeomIter {
- struct istate *stack;
- int flags;
- };
-
- static struct GeomIter *itpool;
- static struct istate *ispool;
-
- #define NewIter(it) if(itpool) { it = itpool; itpool = NULL;} \
- else it = (GeomIter *)malloc(sizeof(GeomIter))
- #define NewIstate(is) if(ispool) { is = ispool; ispool = ispool->parent; } \
- else is = (struct istate *)malloc(sizeof(struct istate))
-
- #define FreeIter(it) if(itpool) GeomFree(it); else itpool = it
- #define FreeIstate(is) (is)->parent = ispool, ispool = is
-
- GeomIter *
- GeomIterate(g, flags)
- Geom *g;
- int flags;
- {
- GeomIter *it;
- register struct istate *is;
-
- NewIter(it);
- it->flags = (flags & 15) | VALID;
- NewIstate(is);
- it->stack = is;
- is->kind = UNKNOWN;
- is->g = g;
- is->parent = NULL;
- return it;
- }
-
- /*
- * Iterate over an OOGL hierarchy, producing one Transform per call.
- * Returns 1 normally, 0 when no more Transforms remain.
- * Destroys the GeomIter upon returning 0.
- *
- * To make this work as a coroutine we effectively unroll the recursive
- * hierarchy traversal, so please excuse the goto's.
- *
- * For speed, we act as a friend to the List, TList, Inst, and Sphere
- * classes. XXX
- */
- NextTransform(it, T)
- GeomIter *it;
- Transform T;
- {
- register struct istate *is;
- Geom *g;
-
- if(it == NULL)
- return 0;
- if((is = it->stack) == NULL)
- goto gone;
-
- g = is->g;
-
- again:
- switch(is->kind) {
- case UNKNOWN: /* Determine type */
- discover:
- if(g->Class == TlistClass) {
- if(g->magic != TLISTMAGIC) {
- GeomError(0,"NextTransform: Surprise Tlist %x", g);
- goto pop;
- }
- is->kind = TLIST;
- is->seq = 0;
- goto isTLIST;
- }
- if(g->Class == DiscGrpClass) {
- if(g->magic != DISCGRPMAGIC) {
- GeomError(0,"NextTransform: Surprise DiscGrp %x", g);
- goto pop;
- }
- is->kind = DISCGRP;
- is->seq = 0;
- goto isDISCGRP;
- }
- if(g->Class == ListClass) {
- if(g->magic != LISTMAGIC) {
- GeomError(0,"NextTransform: Surprise List %x", g);
- goto pop;
- }
- is->kind = LIST;
- goto isLIST;
- }
- if(g->Class == InstClass || g->Class == SphereClass) {
- register Inst *inst = (Inst *)g;
-
- if(inst->magic != INSTMAGIC && inst->magic != SPHEREMAGIC) {
- GeomError(0,"NextTransform: Surprise Inst %x", g);
- goto pop;
- }
- if(inst->tlist == NULL) {
- /*
- * Just use this transform. We're a leaf, so return it now.
- * Also pop stack for next iteration.
- */
- if(is = is->parent)
- TmConcat(inst->axis, is->Ti, T);
- else
- TmCopy(inst->axis, T);
- FreeIstate(it->stack);
- it->stack = is;
- return 1;
- } else {
- /*
- * Inst has a child.
- * The axis field is *ignored* in this case; just
- * traverse the child.
- */
- is->g = g = inst->tlist;
- /*is->kind = UNKNOWN;*/
- goto discover;
- }
- }
- /* Other objects aren't relevant for NextTransform(), so discard. */
- goto pop;
-
- case TLIST:
- isTLIST:
- {
- register Tlist *TL = (Tlist *)g;
- register float (*Tp)[4]; /* ought to be ``Transform *Tp'' */
-
- if(is->seq >= TL->nelements)
- goto pop;
-
- Tp = TL->elements[is->seq++];
-
- if(TL->tlist != NULL && !(it->flags & SHALLOW)) {
- if(is->parent)
- TmConcat(*Tp, is->parent->Ti, is->Ti);
- else
- TmCopy(*Tp, is->Ti);
- g = TL->tlist;
- goto push;
- }
-
- /* We're a leaf -- return a matrix now */
- if(is->parent)
- TmConcat(*Tp, is->parent->Ti, T);
- else
- TmCopy(*Tp, T);
- return 1;
- }
-
- case DISCGRP:
- isDISCGRP:
- {
- register DiscGrp *dg = (DiscGrp *)g;
- register float (*Tp)[4]; /* ought to be ``Transform *Tp'' */
-
- if(is->seq >= dg->big_list->num_el)
- goto pop;
-
- Tp = dg->big_list->el_list[is->seq++].tform;
-
- /* if it's another discrete group ... */
- if(dg->geom != NULL &&
- dg->geom->magic == DISCGRPMAGIC && !(it->flags & SHALLOW)) {
- if(is->parent)
- TmConcat(*Tp, is->parent->Ti, is->Ti);
- else
- TmCopy(*Tp, is->Ti);
- g = dg->geom;
- goto push;
- }
-
- /* We're a leaf -- return a matrix now */
- if(is->parent)
- TmConcat(*Tp, is->parent->Ti, T);
- else
- TmCopy(*Tp, T);
- return 1;
- }
-
- case LIST:
- isLIST:
- {
- /* Might need some intra-List state too if List format
- * gets fancier -- if we have one List object which contains a
- * bundle of Geom's.
- */
- register List *L = (List *)g;
-
- if(L == NULL)
- goto pop;
- while(L->car == NULL) {
- L = L->cdr;
- if(L == NULL)
- goto pop;
- }
- g = L->car;
- is->g = (Geom *)L->cdr;
- if(is->parent)
- TmCopy(is->parent->Ti, is->Ti);
- else
- TmIdentity(is->Ti);
- goto push;
- }
-
- default:
- GeomError(1,"NextTransform: called with invalid GeomIter (%x)", it);
- return 0;
- }
-
- push: /* Push g as a new element */
- /* is->Ti *must* be set correctly before getting here! */
- NewIstate(is);
- is->g = g;
- is->parent = it->stack;
- it->stack = is;
- goto discover; /* Recurse */
-
- pop:
- is = is->parent;
- FreeIstate(it->stack);
- it->stack = is;
- if(is != NULL) {
- g = is->g;
- goto again; /* Recurse -- type already determined */
- }
- /* stack empty -- fall into gone: */
-
- gone:
- it->flags = 0;
- it->stack = NULL;
- FreeIter(it);
- return 0;
- }
-
- void
- DestroyIter(it)
- GeomIter *it;
- {
- if((it->flags & 0xfffffff0) == VALID) {
- it->flags = 0;
- it->stack = NULL;
- FreeIter(it);
- } else {
- GeomError(1,"DestroyIter -- already destroyed %x", it);
- }
- }
-